#ifndef __EKOS_KENREL_MEM_H__
#define __EKOS_KENREL_MEM_H__

int mem_init();

/* physical memory */

extern uint32_t   mlayout_count;
extern physaddr_t mlayout_addr[MEMMAP_MAXCOUNT << 1];

#define PADDR(kva) ((physaddr_t)(kva) - KBASE)
#define KADDR(pa)  (void *)((pa) + KBASE)

#define PA_VAILD(addr)  (mlayout_bin_search(addr) & 1 == 0)
int pmemory_layout_bin_search(physaddr_t addr);

extern uint32_t ppage_count;
extern struct ppage_t *ppages;
extern mcs_lock_t ppage_alloc_lock;
extern struct ppage_t *ppage_free_head;
extern struct ppage_t *ppage_fh_per_cpu[SMP_MAX_COUNT];
extern int ppage_fc_per_cpu[SMP_MAX_COUNT];

#define PPAGE_ALLOC_BATCH_COUNT 32

int  ppage_alloc(physaddr_t *addr, uint16_t status);
int  ppage_inc_ref(physaddr_t addr);
int  ppage_add_ref(physaddr_t addr, int ref);
void ppage_free(physaddr_t addr);
int  ppage_dec_ref(physaddr_t addr);

/* virtual memory */

extern struct segdesc_t gdt[GDT_COUNT];
/* The symbols is defined in kernel.S */
/* {{{ */
/* Lock for vpd entry */
extern volatile spin_lock_t  vpd_lock[];
/* The mapping of current VPT */
extern volatile ptab_entry_t vpt[];
/* Mapping of VPD inside vpt */
extern volatile pdir_entry_t vpd[];
/* Get the temp page address for current stack */
void *get_tpage();
/* }}} */

void      *set_tpage(physaddr_t addr);
void       set_page_map(void *vaddr, uint32_t pte);
physaddr_t phys_addr(void *ptr);

#define    FA_COW    1
#define    FA_AWA    2

#define    fix_addr(args ...) __fix_addr(0, args)
int        __fix_addr(int verbose, void *addr, ptab_entry_t *create, ...);

/* These macros define a simple method for using tpage space,
   all the data should not exceed the 4K page boundary */
#define BEGIN_TPAGE(ADDR, VAR)					  \
	 { uint32_t __old = vpt[PAGE_NUM(get_tpage())]; \
	   VAR = set_tpage(ADDR)

#define EXIT_TPAGE set_page_map(get_tpage(), __old)
#define END_TPAGE set_page_map(get_tpage(), __old); }

int vpd_mark_shared(int idx);
int vpt_mark_shared(int idx);

int vpd_alloc_temp(int idx);
int vpt_alloc_temp(int idx);

int fork_mem(void);

void mem_enqueue_pf_info_wait(struct pf_info_t *pf);
void mem_dequeue_pf_info(struct pf_info_t *pf);

#endif
